package com.syyo.admin.config.security.config;

import com.syyo.admin.common.anno.AnonymousAccess;
import com.syyo.admin.utils.SpringContextHolder;
import com.syyo.admin.common.constant.SettingsConstant;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/**
 * @Auther: wangzhong
 * @Date: 2020/4/15 14:35
 * @Description:
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SettingsConstant settingsConstant;

    private final TokenProvider tokenProvider;
    private final MyAccessDeniedHandler myAccessDeniedHandler;
    private final MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    private final ApplicationContext applicationContext;

    public WebSecurityConfig(
            TokenProvider tokenProvider,
            MyAccessDeniedHandler myAccessDeniedHandler,
            MyAuthenticationEntryPoint myAuthenticationEntryPoint,
            ApplicationContext applicationContext) {
        this.tokenProvider = tokenProvider;
        this.myAccessDeniedHandler = myAccessDeniedHandler;
        this.myAuthenticationEntryPoint = myAuthenticationEntryPoint;
        this.applicationContext = applicationContext;

    }

//    @Bean
//    GrantedAuthorityDefaults grantedAuthorityDefaults() {
//        // 去除 ROLE_ 前缀
//        return new GrantedAuthorityDefaults("");
//    }

    @Bean
    public SpringContextHolder springContextHolder() {
        return new SpringContextHolder();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 密码加密方式
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 搜寻匿名标记 url： @AnonymousAccess
        //获取所有的请求路劲
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
        Set<String> anonymousUrls = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
            HandlerMethod handlerMethod = infoEntry.getValue();
            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            if (null != anonymousAccess) {
                //请求方法上有@AnonymousAccess注解的都算匿名访问
                anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                System.out.println(anonymousUrls);
            }
        }
        //设置访问权限
        http.csrf().disable()
                //异常处理
                .exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                .accessDeniedHandler(myAccessDeniedHandler)

                // 不创建会话
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 静态资源等等
                .and()
                .authorizeRequests()
                .antMatchers(
                        HttpMethod.GET,
                        "/swagger-resources/**",
                        "/swagger-ui.html",
                        "/v2/api-docs",
                        "/webjars/**",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/webSocket/**"
                ).permitAll()
                //匿名访问的接口
                .antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
                // 放行OPTIONS请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 所有请求都需要认证
                .anyRequest().authenticated()
                .and().apply(securityConfigurerAdapter());//添加token过滤器

        http.headers().frameOptions().disable(); //关闭disable
        // 关闭 Security 的校验
        if (!settingsConstant.getSecuritySwitch()) {
            http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll();
        }
    }

    private TokenConfigurer securityConfigurerAdapter() {
        return new TokenConfigurer(tokenProvider, settingsConstant);
    }
}
